#include<bits/stdc++.h>

using namespace std;

struct Edge {
    int x, y, w;

    bool operator<(const Edge &that) const {
        return this->w < that.w;
    }
} e[100];

int n, m;
const int maxn = 100;
int F[maxn];

void Show(int n) {
    for (int i = 1; i <= n; i++) {
        cout << i << "<-" << F[i] << endl;
    }
}

/**
 * 并查集的初始化:把数组F[i](1<=i <=n )设置为F[i]=i
 * @param n
 */
void Init(int n) {
    for (int i = 1; i <= n; i++)F[i] = i;
}

/**
 * 并查集找根节点：寻找x所在的那个树的树根
 * @param x
 * @return
 */
int Find(int x) {
    if (x == F[x]) {
        return x;//说明x就是树根
    } else {
        return F[x] = Find(F[x]);//递归的寻找 F[x]的根,路径压缩
    }
}
/**
 * 合并x,y所在的子树为一棵树
 * @param x
 * @param y
 * @return
 */
bool Union(int x, int y) {
    int fx = Find(x);
    int fy = Find(y);
    if (fx == fy)return false;//不用合并,xy已经在一棵树上
    F[fy] = fx;//把 fy所在的子树都合并到fx这个树上，fx是合并后的树根
    return true;
}

/**
 * 计算连通分支数，（森林里树个数量）
 * @param n
 * @return
 */
int Count(int n) {
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        if (F[i] == i) {
            ++cnt;
        }
    }
    return cnt;
}
/**
 * 最小生成树的克鲁斯卡尔算法（贪心算法）边集排序+并查集判环
 * 算法复杂度：mlogm（边集排序开销）+O(n)（并查集合并查找开销） 适合边较少的情况（稀疏图）
 * @param E
 * @param m
 * @param n
 * @return
 */
int Kruskal(Edge E[], int m, int n) {
    sort(E, E + m);
    Init(n);
    int tot = 0;
    int cnt = 0;
    for (int i = 0; i < m; i++) {
        if (!Union(E[i].x, E[i].y))continue;
        tot += E[i].w;
        ++cnt;
        if (cnt == n - 1)break;
    }
    if (cnt < n - 1)return -1;//原图就不连通
    return tot;
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        cin >> e[i].x >> e[i].y >> e[i].w;

    }
    cout << Kruskal(e, m, n) << endl;
    return 0;
}